﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using Data.GameData.Entities;

namespace Data.GameData
{
    public class StarSystemInformation : GameObject
    { 
        // Declare the event using EventHandler<T>
        public static event EventHandler<BasicEventArgs> RaiseSystemInfomationChangedEvent;

        #region Attributes
        private EStarSystemInformation dbStarSystemInformation;
        private static Dictionary<Guid, StarSystemInformation> starSystemInfoList = new Dictionary<Guid, StarSystemInformation>();

        private int mapId;
        private Guid systemId;
        private Guid ownerId;
        private Guid raceId;
        private bool homeSystem;
        private string name;

        // Known System Warp Points
        #endregion

        #region Constructors
        public StarSystemInformation(Guid sysId, Guid raceId, int mapId, string name)
        {
            dbStarSystemInformation = new EStarSystemInformation();

            this.mapId = mapId;
            this.raceId = raceId;
            this.systemId = sysId;
            this.name = name;
            this.homeSystem = false;

            MarkNew();
        }
        
        public StarSystemInformation(Guid id)
        {
            dbStarSystemInformation = new EStarSystemInformation();

            if (id != Guid.Empty)
            {
                dbStarSystemInformation = EStarSystemInformation.LoadFromDB(id);
                Load();
            }
        }

        private StarSystemInformation(EStarSystemInformation entity)
        {
            this.dbStarSystemInformation = entity;
            Load();
        }
        #endregion

        #region Static Properties
        static public List<StarSystemInformation> StarSystemInfo
        {
            get
            {
                if (starSystemInfoList == null || starSystemInfoList.Count == 0) FetchStarSystemInfoForGame();
                return new List<StarSystemInformation>(starSystemInfoList.Values);
            }
        }

        static public StarSystemInformation GetStarSystemInfo(Guid id)
        {
            if (starSystemInfoList == null || starSystemInfoList.Count == 0) FetchStarSystemInfoForGame();

            if (starSystemInfoList.ContainsKey(id))
                return starSystemInfoList[id];

            return null;
        }

        static public StarSystemInformation[] GetStarSystemInfo()
        {
            return StarSystemInfo.ToArray();
        }
        #endregion

        #region Static Private Methods
        static private void FetchStarSystemInfoForGame()
        {
            if (starSystemInfoList == null || starSystemInfoList.Count == 0)
            {
                starSystemInfoList = new Dictionary<Guid, StarSystemInformation>();

                List<EStarSystemInformation> starSystemList = EStarSystemInformation.GetAllForGame(Game.ActiveGame.Id);
                lock (starSystemInfoList)
                {
                    // Create the Plan business objects
                    foreach (EStarSystemInformation entity in starSystemList)
                    {
                        StarSystemInformation gameObj = new StarSystemInformation(entity);
                        starSystemInfoList.Add(gameObj.Id, gameObj);
                    }
                }
            }
        }
        #endregion

        #region Public Properties
        public int MapId
        {
            get { return mapId; }
            internal set { mapId = value; }
        }

        public Guid RaceId
        {
            get { return raceId; }
            internal set { raceId = value; }
        }

        public Guid SystemId
        {
            get { return systemId; }
            internal set { systemId = value; }
        }

        public Guid OwnerId
        {
            get { return ownerId; }
            set
            {
                if (ownerId == value)
                    return;

                this.OnRaiseSystemInfomationChangedEvent(new BasicEventArgs(Id, BasicEventType.eSTAR_SYSTEM, BasicOperationType.eDELETE));
                ownerId = value;
                MarkDirty();
                this.OnRaiseSystemInfomationChangedEvent(new BasicEventArgs(Id, BasicEventType.eSTAR_SYSTEM, BasicOperationType.eADD));
            }
        }

        public bool IsHomeSystem
        {
            get { return homeSystem; }
            set
            {
                homeSystem = value;
                MarkDirty();
            }
        }

        public string Name
        {
            get { return name; }
            set
            {
                if (name == value)
                    return;

                name = value;
                MarkDirty();
                this.OnRaiseSystemInfomationChangedEvent(new BasicEventArgs(Id, BasicEventType.eSTAR_SYSTEM, BasicOperationType.eMODIFY));
            }
        }
        #endregion

        #region BaseObject overrides - Save, Update, etc
        public override void Save()
        {
            // Save links this is dependent on

            // Save this
            base.Save();

            // Save link dependent on this
        }

        //public static void SaveAll()
        //{
        //    foreach (StarSystemInformation starSystemInfo in starSystemInfoList.Values)
        //    {
        //        starSystemInfo.Save();
        //    }
        //}

        public static void SaveAllForRace(Guid id)
        {
            foreach (StarSystemInformation starSystemInfo in starSystemInfoList.Values.Where(info => info.RaceId == id))
            {
                starSystemInfo.Save();
            }
        }

        internal override void Update()
        {
            if (MarkedToDelete)
            {
                // Delete dependencies

                DeleteNow();
            }
            else //if(IsNew || IsDirty)
            {
                if (IsNew)
                {
                    if (starSystemInfoList == null) starSystemInfoList = new Dictionary<Guid, StarSystemInformation>();
                    starSystemInfoList.Add(this.Id, this);
                }

                SaveValues();
                dbStarSystemInformation.SaveToDB(IsNew);
            }
        }

        internal override void DeleteNow()
        {
            if (dbStarSystemInformation.Values == null)
                dbStarSystemInformation.Values = new Stitch.Database.DBRow();

            dbStarSystemInformation.Values["id"] = Id;

            dbStarSystemInformation.Delete();

            //
            starSystemInfoList.Remove(Id);
            MarkDeleted();
        }

        internal override void SaveValues()
        {
            if (dbStarSystemInformation.Values == null)
                dbStarSystemInformation.Values = new Stitch.Database.DBRow();

            dbStarSystemInformation.Values["id"] = Id;
            dbStarSystemInformation.Values["raceId"] = RaceId;
            dbStarSystemInformation.Values["gameId"] = Game.ActiveGame.Id;
            dbStarSystemInformation.Values["mapId"] = MapId;
            dbStarSystemInformation.Values["systemId"] = SystemId;
            dbStarSystemInformation.Values["ownerId"] = OwnerId;
            dbStarSystemInformation.Values["homeSystem"] = IsHomeSystem.ToString();
            dbStarSystemInformation.Values["name"] = Name;
        }

        internal override void LoadValues()
        {
            if (dbStarSystemInformation.Values == null)
                return;

            Id = dbStarSystemInformation.Values["id"];
            MapId = dbStarSystemInformation.Values["mapId"];
            RaceId = dbStarSystemInformation.Values["raceId"];
            SystemId = dbStarSystemInformation.Values["systemId"];
            OwnerId = dbStarSystemInformation.Values["ownerId"];
            IsHomeSystem = string.Compare(dbStarSystemInformation.Values["homeSystem"], "True") == 0;
            Name = dbStarSystemInformation.Values["name"];
        }

        internal override void InitialiseObject()
        {
        }
        #endregion

        #region Protected Event Managers
        protected virtual void OnRaiseSystemInfomationChangedEvent(BasicEventArgs e)
        {
            // Make a temporary copy of the event to avoid possibility of
            // a race condition if the last subscriber unsubscribes
            // immediately after the null check and before the event is raised.
            EventHandler<BasicEventArgs> handler = RaiseSystemInfomationChangedEvent;

            // Event will be null if there are no subscribers
            if (handler != null)
            {
                // Use the () operator to raise the event.
                handler(this, e);
            }
        }
        #endregion
    }
}